package com.libinshen.wxpay.common.util.wxUtils;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Value;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/***
 *此类为微信登录相关的工具封装类.微信登录参考：
 * https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Development_Guide.html
 * https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/Authorized_API_call_UnionID.html
 */
public class WxLoginUtils {

    private static final String getCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize";
    private static final String refreshTokenUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token";
    private static final String getUserInfo = "https://api.weixin.qq.com/sns/userinfo";

    //获取到临时票据之后重定向到哪里
    private static final String redirectUrl = "";

    @Value("${wx.wechat.appId}")//一定要注意这个注解是哪个包里面的
    private static String appId;

    @Value("${wx.wechat.appSecret}")//一定要注意这个注解是哪个包里面的
    private static String appSecret;
    private HashMap<String, String> map;


    /***
     * 向前端返回获取 请求微信服务器的临时票据code
     * https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
     * @return
     */
    public static String getCodeUrl(String scope) {
        try {
            StringBuffer url = new StringBuffer();
            url.append("redirect:")
                    .append(getCodeUrl)
                    .append("?appid=")
                    .append(appId)
                    .append("&redirect_uri=")
                    .append(URLEncoder.encode(redirectUrl, "UTF-8"))  //根据微信开放平台规定，最好使用URLEncoder.encode对URL进行处理
                    .append("&response_type=code")
                    .append("&scope=snsapi_userinfo&state=")
                    .append(scope)
                    .append("#wechat_redirect");
            return url.toString();
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("URL格式化异常");
        }
    }


    /**
     * 通过临时票据code获取微信AccessToken以及openId
     * such as :https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
     *
     * @param code
     * @return
     */
    public static Map<String, String> getAccessToken(String code) {
        HashMap<String, String> map = new HashMap<>();
        if (StringUtils.isEmpty(code)) {
            //TODO return CommonResult.error().setMessage("微信code不能为空");
        }

        //通过code构建向微信服务器获取accessToken的URL
        StringBuilder baseAccessTokenUrl = new StringBuilder()
                .append(code)
                .append("?appid=%s")
                .append("&secret=%s")
                .append("&code=%s")
                .append("&grant_type=authorization_code");
        String getAccessTokenUrl = String.format(baseAccessTokenUrl.toString(),
                appId,
                appSecret,
                code);

        String result = null;
        try {
            //向微信服务器发送请求获取accessToken 以及 openid
            result = HttpUtil.get(getAccessTokenUrl);
            System.out.println("使用code换取的accessToken为" + result);
            System.out.println("拼接的accessTokenUrl为：" + getAccessTokenUrl);
        } catch (Exception e) {
            //TODO return CommonResult.error().setMessage("验证码错误");
        }

        JSONObject resultJson = JSONObject.parseObject(result);
        if (resultJson.getString("errcode") != null) {
            //TODO return CommonResult.error().setMessage("返回的用户信息异常");
        }

        String accessToken = resultJson.getString("access_token");
        System.out.println("accessToken为 :" + accessToken);
        String openid = resultJson.getString("openid");
        System.out.println("openid为:" + openid);//TODO
        map.put("accessToken", accessToken);
        map.put("openid", openid);
        return map;
    }

    /**
     * 向AccessToken
     * 第三步：刷新 access_token 有效期
     * access_token 是调用授权关系接口的调用凭证，由于 access_token 有效期（目前为 2 个小时）较短，
     * 当 access_token 超时后，可以使用 refresh_token 进行刷新，access_token 刷新结果有两种：
     * <p>
     * 1. 若access_token已超时，那么进行refresh_token会获取一个新的access_token，新的超时时间；
     * 2. 若access_token未超时，那么进行refresh_token不会改变access_token，但超时时间会刷新，相当于续期access_token。
     * such as:  https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=APPID&grant_type=refresh_token&refresh_token=REFRESH_TOKEN
     * 官方参数说明：
     * 参数	是否必须	说明
     * appid	是	应用唯一标识
     * grant_type	是	填 refresh_token
     * refresh_token	是	填写通过 access_token 获取到的 refresh_token 参数
     * 正确的返回：
     * {
     * "access_token": "ACCESS_TOKEN",
     * "expires_in": 7200,
     * "refresh_token": "REFRESH_TOKEN",
     * "openid": "OPENID",
     * "scope": "SCOPE"
     * }
     * 错误的返回说明：
     * { "errcode": 40030, "errmsg": "invalid refresh_token" }
     *
     * @param refreshToken
     * @return
     */
    public static Map refreshToken(String refreshToken) {
        StringBuffer url = new StringBuffer();
        url.append(refreshTokenUrl)
                .append("?appid=")
                .append(appId)
                .append("&grant_type=refresh_token&refresh_token=")
                .append(refreshToken);
        String result = HttpUtil.get(url.toString());

        Map map = JSONObject.parseObject(result, Map.class);
        if (null == map.get("errcode")) {
            System.out.println("返回的access_token is:" + map.get("access_token"));
            System.out.println("返回的refresh_token is:" + map.get("refresh_token"));
            return map;
        } else {
            throw new RuntimeException("刷新access_token出错");
        }
    }


    /**
     * 获取用户信息
     * {
     * "openid": "OPENID",
     * "nickname": "NICKNAME",
     * "sex": 1,
     * "province": "PROVINCE",
     * "city": "CITY",
     * "country": "COUNTRY",
     * "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
     * "privilege": ["PRIVILEGE1", "PRIVILEGE2"],
     * "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
     * }
     *
     * @param accessToken
     * @param openid
     * @return
     */
    public static Map getUserInfo(String accessToken, String openid) {
        StringBuffer url = new StringBuffer();
        url.append(getUserInfo)
                .append("?access_token=")
                .append(accessToken)
                .append("&openid=")
                .append(openid)
                .append("&lang=zh_CN");
        String result = HttpUtil.get(url.toString());

        Map map = JSONObject.parseObject(result, Map.class);
        if (null == map.get("errcode")) {
            System.out.println("返回的openid is:" + map.get("openid"));
            System.out.println("返回的nickname is:" + map.get("nickname"));
            System.out.println("返回的sex is:" + map.get("sex"));
            System.out.println("返回的province is:" + map.get("province"));
            System.out.println("返回的city is:" + map.get("city"));
            System.out.println("返回的country is:" + map.get("country"));
            System.out.println("返回的headimgurl is:" + map.get("headimgurl"));
            System.out.println("返回的unionid is:" + map.get("unionid"));
            return map;
        } else {
            throw new RuntimeException("刷新access_token出错");
        }
    }
}
